技巧21 不带缓存的重新构建
使用Dockerfile进行构建时会用到一项有用的缓存功能:只有当命令发生更改时才会重建已构建的步骤。代码清单4-5展示了第1章里介绍的todo应用的一次重新构建的输出结果。
代码清单4-5 带缓存的重新构建
$ docker build .
Sending build context to Docker daemon 2.56 kB
Sending build context to Docker daemon
Step 0 : FROM node
---> 91cbcf796c2c
Step 1 : MAINTAINER ian.miell@gmail.com
---> Using cache ⇽--- 表明此次构建使用了缓存
---> 8f5a8a3d9240 ⇽--- 指定缓存的镜像/层ID
Step 2 : RUN git clone -q https://github.com/docker-in-practice/todo.git
---> Using cache
---> 48db97331aa2
Step 3 : WORKDIR todo
---> Using cache
---> c5c85db751d6
Step 4 : RUN npm install > /dev/null
---> Using cache
---> be943c45c55b
Step 5 : EXPOSE 8000
---> Using cache
---> 805b18d28a65
Step 6 : CMD npm start
---> Using cache
---> 19525d4ec794
Successfully built 19525d4ec794 ⇽--- 最后镜像是“重新构建”了,但是实际上没有任何变动
这样做的确有用而且省时,但是它往往并不是用户预期的。以前面的Dockerfile为例,假设用户已经修改了源码并且推送到了Git仓库。然而,新的代码并不会被签出,因为 git clone
命令并没有更改。就Docker构建的过程来看,它们是相同的,因此Docker会复用之前缓存的镜像。在这些情况下,用户想要的是在不使用缓存的情况下重新构建镜像。
问题
想要使用Dockerfile进行重新构建时不使用现有缓存。
解决方案
想要在重新构建时强制指定不使用镜像缓存,请在执行 dockerbuild
时带上 –-no-cache
标志。如代码清单4-6所示,使用 --no-cache
运行前面的构建。
代码清单4-6 不使用缓存强制触发一次重新构建
$ docker build --no-cache . ⇽--- 重新构建Docker镜像时带上--no-cache标志来忽略已缓存的镜像层
Sending build context to Docker daemon 2.56 kB
Sending build context to Docker daemon
Step 0 : FROM node
---> 91cbcf796c2c
Step 1 : MAINTAINER ian.miell@gmail.com
---> Running in ca243b77f6a1 ⇽--- 此时不再提示有缓存
---> 602f1294d7f1 ⇽--- 中间镜像的ID和之前列表里的有所不同
Removing intermediate container ca243b77f6a1
Step 2 : RUN git clone -q https://github.com/docker-in-practice/todo.git
---> Running in f2c0ac021247
---> 04ee24faaf18
Removing intermediate container f2c0ac021247
Step 3 : WORKDIR todo
---> Running in c2d9cd32c182
---> 4e0029de9074
Removing intermediate container c2d9cd32c182
Step 4 : RUN npm install > /dev/null
---> Running in 79122dbf9e52
npm WARN package.json todomvc-swarm@0.0.1 No repository field.
---> 9b6531f2036a
Removing intermediate container 79122dbf9e52
Step 5 : EXPOSE 8000
---> Running in d1d58e1c4b15
---> f7c1b9151108
Removing intermediate container d1d58e1c4b15
Step 6 : CMD npm start
---> Running in 697713ebb185
---> 74f9ad384859
Removing intermediate container 697713ebb185
Successfully built 74f9ad384859 ⇽--- 一个新的镜像构建出来了
输出内容显示没有提到缓存,而且每个中间层的ID和代码清单4-5里的输出也有所不同。
在其他情况下也有可能遇到类似的问题。我们在早期使用Dockerfile的时候就遇到了一些坑,当网络抖动时一条命令可能无法从网络上正确地检索到某些东西,但是它不会报错。我们持续调用 dockerbuild
,但是生成的bug不会消失!这是因为“坏”镜像已经放进了缓存,而我们当时并不了解Docker缓存的工作方式。最终我们搞明白了。
讨论
一旦完成最终版本的Dockerfile,删除缓存可能是一个有用的健全性检查,这样可以确保它自顶向下是工作的,特别是当用户在公司里使用内部的Web资源而同时又在迭代Dockerfile的过程中可能做了一些改动的时候。如果用户正在使用的是 ADD
,那么不会出现这样的情况,因为Docker会在每次下载文件时检查是否有做过改动,但是当用户相当肯定它会保持不变并且只想继续编写Dockerfile的其他部分时,这样的做法可能会很烦人。